#include <iostream>
#include <string>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>

#include "Sock.hpp"
#include "log.hpp"
#include "err.hpp"

#define READ_EVENT (0x1)        // 读事件
#define WRITE_EVENT (0x1 << 1)  // 写事件
#define EXCEPT_EVENT (0x1 << 2) // 异常事件

// 事件管理
struct FdEvent
{
    int fd;
    uint8_t event;
    std::string clientIp;
    uint16_t clientPort;
};

const static uint16_t defaultport = 8888; // 默认端口号
const static int N = sizeof(fd_set) * 8;  // 默认事件管理集大小
const static int defaultfd = -1;          // 默认文件描述符
const static int defaultevent = 0;        // 默认关心事件
typedef FdEvent type_t;
// timeval waittime={2,0};

class SelectServer
{
public:
    SelectServer(uint16_t port = defaultport) : _port(port)
    {
    }

    void InitServer()
    {
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        // 初始化事件管理集
        for (int i = 0; i < N; ++i)
        {
            fdarray[i].fd = defaultfd;
            fdarray[i].event = defaultevent;
            fdarray[i].clientPort = 0;
        }
    }
    // 连接获取
    void Accept()
    {
        std::string clientIp;
        uint16_t clientPort;
        int sock = _listensock.Accept(&clientIp, &clientPort);
        std::string name = "[" + clientIp + ":" + std::to_string(clientPort) + "]";
        if (sock < 0)
            return;

        int i = 1;
        for (; i < N; ++i)
        {
            if (fdarray[i].fd != defaultfd)
                continue;
            fdarray[i].fd = sock;
            fdarray[i].event = READ_EVENT; // 关心读事件
            fdarray[i].clientIp = clientIp;
            fdarray[i].clientPort = clientPort;
            logMessage(Info, "%s连接到来,sock:%d", name.c_str(), sock);
            break;
        }
        // 连接管理已打上限
        if (i >= N)
        {
            std::string echo = "当前连接已满,请稍后尝试";
            send(sock, echo.c_str(), echo.size(), 0);
            close(sock);
        }
    }

    void Recv(int indix)
    {
        char buffer[1024];
        int n = recv(fdarray[indix].fd, buffer, sizeof(buffer) - 1, 0);
        if (n < 0)
            logMessage(Warning, "recv error,%d:%s", errno, strerror(errno));
        else if (n > 0)
        {
            buffer[n] = '\0';
            std::cout << "client# " << buffer << std::endl;
            // 返回响应
            std::string echo = "[server echo] ";
            echo += buffer;
            send(fdarray[indix].fd, echo.c_str(), echo.size(), 0);
        }
        else
        {
            // 客户端关闭连接
            logMessage(Info, "client quit...%d", fdarray[indix].fd);
            close(fdarray[indix].fd);
            fdarray[indix].fd = defaultfd;
        }
    }

    void HandlerEvent(fd_set &rfds)
    {
        for (int i = 0; i < N; ++i)
        {
            if (fdarray[i].fd == defaultfd)
                continue;
            // 连接事件到来
            if (fdarray[i].event & READ_EVENT)
            {
                if (fdarray[i].fd == _listensock.Fd() && FD_ISSET(fdarray[i].fd, &rfds))
                    Accept();
                else if (fdarray[i].fd != _listensock.Fd() && FD_ISSET(fdarray[i].fd, &rfds))
                {
                    Recv(i);
                }
            }
        }
    }

    void Start()
    {
        fdarray[0].fd = _listensock.Fd();
        fdarray[0].event=READ_EVENT;
        while (true)
        {
            fd_set rfds; // 读事件集
            FD_ZERO(&rfds);
            int maxfd = fdarray[0].fd;
            // 设置需要关心的读事件
            for (int i = 0; i < N; ++i)
            {
                if (fdarray[i].fd == defaultfd)
                    continue;
                FD_SET(fdarray[i].fd, &rfds);
                // 获取最大的fd
                if (fdarray[i].fd > maxfd)
                    maxfd = fdarray[i].fd;
            }
            // 最后时间NULL，代表阻塞式等待
            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            switch (n)
            {
            case 0:
                logMessage(Info, "timeout...%d:%s", errno, strerror(errno));
                break;
            case -1:
                logMessage(Warning, "select error,&d:%s", errno, strerror(errno));
                break;
            default:
                // 有连接到来
                HandlerEvent(rfds);
                continue;
            }
        }
    }

    ~SelectServer()
    {
    }

private:
    uint16_t _port;    // 端口号
    Sock _listensock;  // 监听套接字
    type_t fdarray[N]; // 连接套接字管理数组
};